package view;

import java.util.ArrayList;
import java.util.Iterator;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;

import com.sun.opengl.util.j2d.TextRenderer;
import colors.Color;

import mathematics.geometry.Geometry;
import mathematics.geometry.SegmentGeometry;
import model.RoomModel;
import model.trajectory.RoomTrajectoryModel;
import model.trajectory.TargetModel;
import settings.Settings;
import utils.*;
import view.trajectory.BaseTrajectoryView;
import view.trajectory.RoomTrajectoryView;
import graphics.complexe.NodeGraphicObject;
import graphics.complexe.PolygonGraphicObject;
import graphics.engine.ProgramShader;

public class RoomView extends BaseHybridView
{
	public int currentSubTrajectoryIndex = 0;
	public int currentSubTrajectoryHighlightedIndex = 0;
	
	private ArrayList<DoorView> doors;
	private ArrayList<AdjacencyView> adjacencies;
	private ArrayList<RoomTrajectoryView> subtrajectories;
	
	private TextRenderer textRenderer;
	private int texture;
	
	private GraphView graphView;
	
	private double maximumWidthAtCenter = 0;
	private double maximumHeightAtCenter = 0;
	
	public RoomView(GL gl, TextRenderer textRenderer, RoomModel model)
	{
		super(model);
		
		this.textRenderer = textRenderer;
		this.label = new Label(this.textRenderer, model.getID()+"", model.getCenter());
		
		this.doors = new ArrayList<DoorView>();
		this.adjacencies = new ArrayList<AdjacencyView>();
		this.subtrajectories = new ArrayList<RoomTrajectoryView>();
		
		this.expendedShape = new PolygonGraphicObject(gl, model.getGeometry());
		this.expendedShape.setBaseColor(Settings.RoomColor);

		this.nodeShape = new NodeGraphicObject(gl);
		this.nodeShape.setPosition(new Point3D(model.getCenter().x() , model.getCenter().y(), 0.0f));
		this.nodeShape.setScale(new Vector3D(nodeSize, nodeSize, nodeSize));	
		this.nodeShape.setBaseColor(new Color(1.0f, 10f, 1.0f, 1.0f));
		this.nodeShape.setOutlineColor(new Color(0.0f, 0.0f, 0.0f, 1.0f));

		this.graphView = new GraphView(gl, ((RoomModel)this.getModel()).getMatrix());
		
		//this.expendedShapeLabelPosition = Point3D.sum(((PolygonGeometry)model.getGeometry()).getUpperLeftPoint(), new Vector3D(20, -70));
		this.expendedShapeLabelPosition = Point3D.sum(model.getCenter(), new Vector3D(50, 50));
		this.nodeShapeLabelPosition = Point3D.sum(model.getCenter(), new Vector3D(50, 50));
		this.label.setPosition(this.expendedShapeLabelPosition);	
		
		this.setMaximumHeightAtCenter(model.getGeometry().processIntersectionLength(new SegmentGeometry(new Point3D(model.getCenter().x(), -999999999), new Point3D(model.getCenter().x(),999999999))));
		this.setMaximumWidthAtCenter(model.getGeometry().processIntersectionLength(new SegmentGeometry(new Point3D(-999999999, model.getCenter().y()), new Point3D(999999999, model.getCenter().y()))));

		this.setNodeShape(false);
	}
	
	public void DrawSelection(GLAutoDrawable drawable, ProgramShader programShader)
	{
		if(this.getModel().isSelected)
		{
			if(this.isNodeShape())
			{
				this.nodeShape.DrawSelection(drawable, programShader);
			}
			else
			{
				this.expendedShape.DrawSelection(drawable, programShader);
			}
		}
		
		if(this.getModel().isHighlighted())
		{
			if(this.isNodeShape())
			{
				this.nodeShape.DrawHighlight(drawable, programShader);
			}
			else
			{
				this.expendedShape.DrawHighlight(drawable, programShader);
			}
		}

		if(this.getModel().isSelected || this.getModel().isHighlighted())
		{
			this.Draw(drawable, programShader);
		}
	}
	
	@Override
	public void Draw(GLAutoDrawable drawable, ProgramShader programShader)
	{	
		super.Draw(drawable, programShader);
		if(Settings.HideUnnecessaryObjects && !this.getModel().isSelected && !this.getModel().isHighlighted() && this.subtrajectories.size() == 0)
		{
			Color color = this.nodeShape.getBaseColor();
			color.A = Settings.AlphaUsedForHidding;
			this.nodeShape.setBaseColor(color);
			
			color = this.nodeShape.getOutlineColor();
			color.A = Settings.AlphaUsedForHidding;
			this.nodeShape.setOutlineColor(color);
		}
		else
		{
			Color color = this.nodeShape.getBaseColor();
			color.A = 1.0f;
			this.nodeShape.setBaseColor(color);
			
			color = this.nodeShape.getOutlineColor();
			color.A = 1.0f;
			this.nodeShape.setOutlineColor(color);
		}
		if(this.getNodeDetailLevel() == 2)
		{
			this.graphView.Draw(drawable, programShader);
		}
		else if(this.getNodeDetailLevel() == 1)	
		{
			this.nodeShape.Draw(drawable, programShader);
		}
		else
		{
			this.expendedShape.Draw(drawable, programShader);
		}
	}
	
	public void resetStat()
	{
		this.currentSubTrajectoryIndex = 0;
		this.currentSubTrajectoryHighlightedIndex = 0;
		for(Iterator<DoorView> it = doors.iterator(); it.hasNext();)
		{
			it.next().resetStat();
		}
	}


	public void DrawDoors(GLAutoDrawable drawable, ProgramShader programShader)
	{
		for(Iterator<DoorView> it = this.doors.iterator(); it.hasNext();)
		{
			it.next().Draw(drawable, programShader);
		}
	}
	
	public void DrawAdjacencies(GLAutoDrawable drawable, ProgramShader programShader)
	{
		for(Iterator<AdjacencyView> it = this.adjacencies.iterator(); it.hasNext();)
		{
			it.next().Draw(drawable, programShader);
		}
	}
	
	public void AddDoor(DoorView door)
	{
		this.doors.add(door);
	}
	
	public void AddAdjacency(AdjacencyView adjacency)
	{
		this.adjacencies.add(adjacency);
	}

	public void drawLabel(GLAutoDrawable drawable) {
		// TODO Auto-generated method stub
		if(this.getModel().isHighlighted() || !Settings.HideUnnecessaryObjects || (Settings.HideUnnecessaryObjects && this.subtrajectories.size() > 0))
		{
			this.label.Draw(drawable);
		}
	}

	public Integer getTexture() {
		return texture;
	}

	public void setTexture(Integer integer) {
		this.texture = integer;
		this.expendedShape.setTexture(this.texture);
	}

	public ArrayList<TargetModel> getIntersectedTrajectories(
			Geometry selectionDisk) {
		//for(Iterator<BaseTrajectoryView> it = this.)
		return null;
	}
	
	@Override
	public void setHasChanged(boolean value)
	{
		this.hasChanged = value;
		for(Iterator<DoorView> it = doors.iterator(); it.hasNext();)
		{
			it.next().setHasChanged(value);
		}
		for(Iterator<AdjacencyView> it = adjacencies.iterator(); it.hasNext();)
		{
			it.next().setHasChanged(value);
		}
		for(Iterator<RoomTrajectoryView> it = getSubtrajectories().iterator(); it.hasNext();)
		{
			it.next().setHasChanged(value);
		}
	}

	public void addSubtrajectoryView(RoomTrajectoryView trajView) {
		this.getSubtrajectories().add(trajView);
	}

	public double getMaximumWidthAtCenter() {
		return maximumWidthAtCenter;
	}

	public void setMaximumWidthAtCenter(double maximumWidthAtCenter) {
		this.maximumWidthAtCenter = maximumWidthAtCenter;
	}

	public double getMaximumHeightAtCenter() {
		return maximumHeightAtCenter;
	}

	public void setMaximumHeightAtCenter(double maximumHeightAtCenter) {
		this.maximumHeightAtCenter = maximumHeightAtCenter;
	}

	public ArrayList<RoomTrajectoryView> getSubtrajectories() {
		return subtrajectories;
	}

	public double getTotalMaxOffset() {
		double max = Math.min(this.getMaximumWidthAtCenter(), this.getMaximumHeightAtCenter());
		double offset = (max / 2.0f - this.nodeSize) / (float )(this.getSubtrajectories().size() );
		
		return offset;
	}

	public float getIndexOfSubtrajectory(BaseTrajectoryView subtrajectory) {
		return this.getSubtrajectories().indexOf(subtrajectory);
	}
	
	public float getIndexOfSubtrajectory(BaseTrajectoryView subtrajectory, long time, long beginTime, long endTime) {
		TimeIntervalle timeSpan = new TimeIntervalle(beginTime, endTime);
		int count = 0;
		int hiddenTrajCount = 0;
		for(Iterator<RoomTrajectoryView> it = this.subtrajectories.iterator(); it.hasNext();)
		{
			RoomTrajectoryView view = it.next();
			RoomTrajectoryModel trajModel = (RoomTrajectoryModel)view.getModel();
			
			if( !timeSpan.include(trajModel.intervalle.beginTime) && !timeSpan.include(trajModel.intervalle.endTime))
			{
				hiddenTrajCount++;
			}
			if(view == subtrajectory)
			{
				return count - hiddenTrajCount;
			}
			count++;
		}
		return this.getSubtrajectories().indexOf(subtrajectory) - hiddenTrajCount;
	}
}
